// RectWindow.cpp
// by Charles Mc Auley
// "Programming AutoCAD 2000 with ObjectARX"


#include <acdb.h>		// acdb definitions
#include <adslib.h>		// ads defs
#include <dbsymtb.h>
#include <adeskabb.h>
#include <dbpl.h>		// AcDbPolyline

#include <gepnt2d.h>
#include <gept2dar.h>

#include "RectWindow.h"

RectWindow::RectWindow()
{
	// Initialize the rect Frame Thickness
	// and the internal Window Framing thickness

	rectFrameThk = 2.00;
	intrFrameThk = 1.00;

	rows = 1;
	cols = 1;
	rectFrameLen = 0.0;
	rectFrameHt	 = 0.0;

	lowLeftPt.set(0.0, 0.00);
}

RectWindow::~RectWindow()
{
	// Does nothing
}


void RectWindow::drawWindow(AcDbBlockTableRecord* pBlkTableRecord)
{
	AcGePoint2dArray inrRectFrame;
	AcGePoint2dArray inrTopAr, inrBtmAr, inrLeftAr, inrRtAr;
	AcGePoint2dArray barAr;
	AcGeLineSeg2d inrTop, inrBtm, inrLeft, inrRt;
	AcGeVector2d vec;

	AcGePoint2d sp, ep, ll, lr, ul, ur;

	double frameThk;

	int arSize;
	int rowPos, colPos;
	
	int rows, cols;
	
	if(!drawRectFrame(pBlkTableRecord, inrRectFrame))
	{
		return;
	}

	rows = getWindowRows();
	cols = getWindowCols();

	// Check to see if rows and cols are
	// both 1, in that case we return.

	if(rows == 1 && cols == 1)
	{
		return;
	}

	arSize = inrRectFrame.length();
	if(arSize != 4)
	{
		acutPrintf("\nInvalid internal rect frame array. ");
		return;
	}

	// Get the inner Frame thickness
	frameThk = getIntrFrameThk();

	barAr.setLogicalLength(0);

	// Initialize the line segments
	inrTop.set(inrRectFrame.at(3), inrRectFrame.at(2));
	inrBtm.set(inrRectFrame.at(0), inrRectFrame.at(1));
	inrLeft.set(inrRectFrame.at(0), inrRectFrame.at(3));
	inrRt.set(inrRectFrame.at(1), inrRectFrame.at(2));

	// Now that we have the line segments, get the point
	// along the lines that match the row and col count
	// Note: The getSamplePoints function will include
	// the point at the begining as well at the point
	// at the end of the line. We are interested in the
	// points in the middle.

	inrTop.getSamplePoints(cols + 1, inrTopAr);
	inrBtm.getSamplePoints(cols + 1, inrBtmAr);

	inrLeft.getSamplePoints(rows + 1, inrLeftAr);
	inrRt.getSamplePoints(rows + 1, inrRtAr);

	
	if(cols == 1 && rows > 1)
	{
		// Draw horizontal bars only
		for (rowPos = 1; rowPos < rows; rowPos++)
		{
			// Get the start point and the end point from the array
			sp = inrLeftAr.at(rowPos);
			ep = inrRtAr.at(rowPos);
			
			// from sp and ep calculate ll, lr ,ul, ur
			vec.set(0, (frameThk / 2));
			ll = sp - vec;
			lr = ep - vec;
			ul = sp + vec;
			ur = ep + vec;

			// Add the point to the barAr array
			barAr.append(ll);
			barAr.append(lr);
			barAr.append(ur);
			barAr.append(ul);

			if(!drawIntBar(pBlkTableRecord, barAr))
			{
				acutPrintf("\nError drawing internal horizontal frame member. ");
			}

			barAr.setLogicalLength(0);
		}// for
	}// if

	if(rows == 1 && cols > 1)
	{
		// Draw vertical bars only
		for (colPos = 1; colPos < cols; colPos++)
		{
			// Get the start point and the end point from the array
			sp = inrBtmAr.at(colPos);
			ep = inrTopAr.at(colPos);
			
			// from sp and ep calculate ll, lr ,ul, ur
			vec.set((frameThk / 2), 0);
			ll = sp - vec;
			lr = sp + vec;
			ul = ep - vec;
			ur = ep + vec;

			// Add the point to the barAr array
			barAr.append(ll);
			barAr.append(lr);
			barAr.append(ur);
			barAr.append(ul);

			if(!drawIntBar(pBlkTableRecord, barAr))
			{
				acutPrintf("\nError drawing internal horizontal frame member. ");
			}

			barAr.setLogicalLength(0);
		}// for
	}// if

	if(rows > 1 && cols > 1)
	{
		// Draw both kinds of
		// internal bars

		// Draw all the horizontal bar first
		for(rowPos = 1; rowPos < rows; rowPos++)
		{
			for(colPos = 1; colPos <= cols; colPos++)
			{
				sp.x = inrBtmAr.at(colPos - 1).x;
				sp.y = inrLeftAr.at(rowPos).y;
				ep.x = inrBtmAr.at(colPos).x;
				ep.y = inrLeftAr.at(rowPos).y;

				// Calculate ll, lr, ul, ur
				if(colPos == 1)
				{
					vec.set(0, (frameThk / 2));
					ll = sp - vec;
					ul = sp + vec;
					vec.set( -(frameThk / 2), -(frameThk / 2));
					lr = ep + vec;
					vec.set( -(frameThk / 2), (frameThk / 2));
					ur = ep + vec;
					// Add the point to the barAr array
					barAr.append(ll);
					barAr.append(lr);
					barAr.append(ep);
					barAr.append(ur);
					barAr.append(ul);

					if(!drawIntBar(pBlkTableRecord, barAr))
					{
						acutPrintf("\nError drawing internal horizontal frame member. ");
					}

					barAr.setLogicalLength(0);					
				}
				else if(colPos == cols)
				{
					vec.set((frameThk / 2), (frameThk / 2));
					ul = sp + vec;
					vec.set((frameThk / 2), -(frameThk /2));
					ll = sp + vec;
					vec.set(0, (frameThk / 2));
					lr = ep - vec;
					ur = ep + vec;

					barAr.append(sp);
					barAr.append(ll);
					barAr.append(lr);
					barAr.append(ur);
					barAr.append(ul);

					if(!drawIntBar(pBlkTableRecord, barAr))
					{
						acutPrintf("\nError drawing internal horizontal frame member. ");
					}

					barAr.setLogicalLength(0);					
				}
				else
				{
					vec.set((frameThk / 2), (frameThk / 2));
					ul = sp + vec;
					vec.set((frameThk / 2), -(frameThk /2));
					ll = sp + vec;
					vec.set( -(frameThk / 2), (frameThk / 2));
					ur = ep + vec;
					vec.set( -(frameThk / 2), -(frameThk / 2));
					lr = ep + vec;

					barAr.append(sp);
					barAr.append(ll);
					barAr.append(lr);
					barAr.append(ep);
					barAr.append(ur);
					barAr.append(ul);

					if(!drawIntBar(pBlkTableRecord, barAr))
					{
						acutPrintf("\nError drawing internal horizontal frame member. ");
					}

					barAr.setLogicalLength(0);
				}
			}// for

			colPos = 1;

		}// for

		// Draw all the vertical bars
		for(colPos = 1; colPos < cols; colPos++)
		{
			for(rowPos = 1; rowPos <= rows; rowPos++)
			{
				sp.x = inrBtmAr.at(colPos).x;
				sp.y = inrLeftAr.at(rowPos - 1).y;
				ep.x = inrBtmAr.at(colPos).x;
				ep.y = inrLeftAr.at(rowPos).y;

				if(rowPos == 1)
				{
					vec.set((frameThk / 2), 0);
					ll = sp - vec;
					lr = sp + vec;
					vec.set( -(frameThk / 2), -(frameThk / 2));
					ul = ep + vec;
					vec.set((frameThk / 2), -(frameThk / 2));
					ur = ep + vec;
					// Add the point to the barAr array
					barAr.append(ll);
					barAr.append(lr);
					barAr.append(ur);
					barAr.append(ep);
					barAr.append(ul);

					if(!drawIntBar(pBlkTableRecord, barAr))
					{
						acutPrintf("\nError drawing internal horizontal frame member. ");
					}

					barAr.setLogicalLength(0);					

				}
				else if(rowPos == rows)
				{
					vec.set((frameThk / 2), 0);
					ul = ep - vec;
					ur = ep + vec;
					vec.set ( -(frameThk / 2), (frameThk / 2));
					ll = sp + vec;
					vec.set ( (frameThk / 2), (frameThk / 2));
					lr = sp + vec;
					// Add the point to the barAr array
					barAr.append(sp);
					barAr.append(lr);
					barAr.append(ur);
					barAr.append(ul);
					barAr.append(ll);

					if(!drawIntBar(pBlkTableRecord, barAr))
					{
						acutPrintf("\nError drawing internal horizontal frame member. ");
					}

					barAr.setLogicalLength(0);
				}
				else
				{
					vec.set((frameThk / 2), (frameThk /2));
					lr = sp + vec;
					ul = ep - vec;
					vec.set ( -(frameThk / 2), (frameThk / 2));
					ll = sp + vec;
					ur = ep - vec;

					// Add the point to the barAr array
					barAr.append(sp);
					barAr.append(lr);
					barAr.append(ur);
					barAr.append(ep);
					barAr.append(ul);
					barAr.append(ll);

					if(!drawIntBar(pBlkTableRecord, barAr))
					{
						acutPrintf("\nError drawing internal horizontal frame member. ");
					}

					barAr.setLogicalLength(0);
				}

			}// for

			rowPos = 1;

		}// for
	}// if
}


// Get and Set functions

int RectWindow::getWindowRows() const
{
	return rows;
}

int RectWindow::getWindowCols() const
{
	return cols;
}

double RectWindow::getWindowHeight() const
{
	return rectFrameHt;
}

double RectWindow::getWindowLength() const
{
	return rectFrameLen;
}

AcGePoint2d RectWindow::getWindowStartPoint() const
{
	return lowLeftPt;
}

double RectWindow::getRectFrameThk() const
{
	return rectFrameThk;
}

double RectWindow::getIntrFrameThk() const
{
	return intrFrameThk;
}

void RectWindow::setWindowRows(int rowQty)
{
	rows = rowQty;
}

void RectWindow::setWindowCols(int colQty)
{
	cols = colQty;
}

void RectWindow::setWindowHeight(double windHeight)
{
	rectFrameHt = windHeight;
}

void RectWindow::setWindowLength(double windLength)
{
	rectFrameLen = windLength;
}


void RectWindow::setWindowStartPoint(AcGePoint2d lowLeftPoint)
{
	lowLeftPt = lowLeftPoint;
}

Adesk::Boolean RectWindow::drawRectFrame(AcDbBlockTableRecord* pBlkTableRecord,
										 AcGePoint2dArray& inrRectFrame)
{
	AcGePoint2dArray outrFrame;
	AcDbPolyline* pFrame;
	AcDbObjectId plineId;
	AcGeVector2d vec;
	AcGePoint2d ll, lr, ur, ul;
	AcGePoint2d vrtxPt;
	double len, ht, frameThk;
	Acad::ErrorStatus es;

	// Get the window length, height and start point
	len = getWindowLength();
	ht	= getWindowHeight();
	ll	= getWindowStartPoint();

	// Calculate the other 3 corner points
	// from ll
	vec.set(len, 0);
	lr = ll + vec;
	vec.set(0, ht);
	ur = lr + vec;
	ul = ll + vec;

	// Add the four calculated points to the array
	outrFrame.append(ll);
	outrFrame.append(lr);
	outrFrame.append(ur);
	outrFrame.append(ul);

	pFrame = new AcDbPolyline(4);

	for(int count = 0; count < outrFrame.length(); count++)
	{
		vrtxPt = outrFrame.at(count);
		pFrame->addVertexAt(count, vrtxPt);
	}

	pFrame->setClosed(Adesk::kTrue);

	es = pBlkTableRecord->appendAcDbEntity(plineId, pFrame);
	if(es != Acad::eOk)
	{
		acutPrintf("\nError in drawing window frame. ");
		if(pFrame != NULL)
		{
			delete pFrame;
		}

		return Adesk::kFalse;
	}

	pFrame->close();

	// Get the frame thickness
	frameThk = getRectFrameThk();

	// Offset the four points ll, lr, ur and ul
	// by the frame thicknesss

	vec.set(frameThk, frameThk);
	ll += vec;
	ur -= vec;
	vec.set(-frameThk, frameThk);
	lr += vec;
	vec.set(frameThk, -frameThk);
	ul += vec;

	// Append the newly calculated points
	// to the AcGePoint2dArray parameter
	// inrRectFrame
	inrRectFrame.append(ll);
	inrRectFrame.append(lr);
	inrRectFrame.append(ur);
	inrRectFrame.append(ul);

	pFrame = new AcDbPolyline(4);

	for(count = 0; count < inrRectFrame.length(); count++)
	{
		vrtxPt = inrRectFrame.at(count);
		pFrame->addVertexAt(count, vrtxPt);
	}

	pFrame->setClosed(Adesk::kTrue);

	es = pBlkTableRecord->appendAcDbEntity(plineId, pFrame);
	if(es != Acad::eOk)
	{
		acutPrintf("\nError in drawing window frame. ");
		if(pFrame != NULL)
		{
			delete pFrame;
		}

		return Adesk::kFalse;
	}

	pFrame->close();


	return Adesk::kTrue;
}

Adesk::Boolean RectWindow::drawIntBar(AcDbBlockTableRecord* pBlkTableRecord,
									  AcGePoint2dArray intBarAr)
{
	AcDbPolyline* pBar;
	AcGePoint2d vrtxPt;
	AcDbObjectId plineId;
	Acad::ErrorStatus es;

	pBar = new AcDbPolyline(intBarAr.length());

	for(int count = 0; count < intBarAr.length(); count++)
	{
		vrtxPt = intBarAr.at(count);
		pBar->addVertexAt(count, vrtxPt);
	}

	pBar->setClosed(Adesk::kTrue);

	es = pBlkTableRecord->appendAcDbEntity(plineId, pBar);
	if(es != Acad::eOk)
	{
		acutPrintf("\nError in drawing frame member. ");
		if(pBar != NULL)
		{
			delete pBar;
		}

		return Adesk::kFalse;
	}

	pBar->close();
	
	return Adesk::kTrue;
}



